package br.com.divulgaqui.managedbean;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;

import org.jboss.logging.Logger;

import br.com.divulgaqui.client.EnderecoServiceBeanLocal;
import br.com.divulgaqui.client.PerfilServiceBeanLocal;
import br.com.divulgaqui.client.PessoaFisicaServiceBeanLocal;
import br.com.divulgaqui.client.PessoaJuridicaServiceBeanLocal;
import br.com.divulgaqui.client.PessoaServiceBeanLocal;
import br.com.divulgaqui.client.TelefoneServiceBeanLocal;
import br.com.divulgaqui.client.exception.CNPJIgualException;
import br.com.divulgaqui.client.exception.CPFIgualException;
import br.com.divulgaqui.client.exception.EmailIgualException;
import br.com.divulgaqui.client.exception.EnderecoErradoException;
import br.com.divulgaqui.entity.Endereco;
import br.com.divulgaqui.entity.Perfil;
import br.com.divulgaqui.entity.Pessoa;
import br.com.divulgaqui.entity.PessoaFisica;
import br.com.divulgaqui.entity.PessoaJuridica;
import br.com.divulgaqui.entity.Telefone;
import br.com.divulgaqui.factory.PageFactory;
import br.com.divulgaqui.util.Util;

import com.ocpsoft.pretty.faces.annotation.URLMapping;
import com.ocpsoft.pretty.faces.annotation.URLMappings;

@ManagedBean
@ViewScoped
@URLMappings(mappings={
	@URLMapping(id="cadastroPessoa", pattern="/admin/pessoa/cadastro", viewId="/admin/pessoa/cadastroPessoa.xhtml"),
	@URLMapping(id="atualizaPessoa", pattern="/admin/pessoa/atualizacao", viewId="/admin/pessoa/atualizaPessoa.xhtml")
})
public class PessoaManagendBean extends BaseBean {

	/**
	 * 
	 */
	private static final long serialVersionUID = 2474052136647474158L;

	@EJB
	private PessoaFisicaServiceBeanLocal pessoaFisicaServiceBeanLocal;

	@EJB
	private PessoaJuridicaServiceBeanLocal pessoaJuridicaServiceBeanLocal;

	@EJB
	private EnderecoServiceBeanLocal enderecoServiceBeanLocal;

	@EJB
	private TelefoneServiceBeanLocal telefoneServiceBeanLocal;
	
	@EJB
	private PerfilServiceBeanLocal perfilServiceBeanLocal;
	
	@EJB
	private PessoaServiceBeanLocal pessoaServiceBeanLocal;
	
	private Pessoa pessoa = new Pessoa();
	private String tipoPessoa;
	private String cpf;
	private String cnpj;
	private Telefone telefone = new Telefone();
	private Endereco endereco = new Endereco();
	private List<Perfil> perfis = new ArrayList<Perfil>();
	private List<Endereco> enderecos = new ArrayList<Endereco>();
	private List<Telefone> telefones = new ArrayList<Telefone>();
	private Logger log = Logger.getLogger(PessoaManagendBean.class);
	
	
	@PostConstruct
	void init(){
		setPerfis(perfilServiceBeanLocal.listar());
		pessoa = new Pessoa();
	}

	/**
	 * Método salva pessoa no banco de dados juntamente
	 * com os telefones e endereços.
	 * 
	 * @return {@link PageFactory}.CADASTROPESSOA
	 */
	public String salvarPessoa() {
		if (!Util.isEmpty(getTelefone().getNumero())) {
			addTelefone();// adiciona o telefone não adicionado a lista pelo usuário.
		}
		if (!Util.isEmpty(getEndereco().getLogradouro()) && !Util.isEmpty(getEndereco().getNumero()) && !Util.isEmpty(getEndereco().getBairro()) && !Util.isEmpty(getEndereco().getUf())
				&& !Util.isEmpty(getEndereco().getCidade()) && !Util.isEmpty(getEndereco().getCep())) {
			addEndereco(); // adiciona o endereço não adicionado a lista pelo usuário.
		}
		//se o cpf for preenchido e o id da pessoa for nulo será um novo registro de pessoaFisica.
 		if (Util.isEmpty(pessoa.getId()) && cpf != null && !cpf.equals("")) {
			pessoa = new PessoaFisica(pessoa);
			((PessoaFisica)pessoa).setCpf(cpf);
		}
 		//se o cnpj for preenchido e o id da pessoa for nulo será um novo registro de pessoaJuridica.
		else if (Util.isEmpty(pessoa.getId()) && cnpj != null && !cnpj.equals("")) {
			pessoa = new PessoaJuridica(pessoa);
			((PessoaJuridica)pessoa).setCnpj(cnpj);
		}
 		//adiciona telefones da tela.
		for (Telefone tel : telefones) {
			pessoa.addTelefone(tel);
		}
		//adiciona endereços da tela.
		for (Endereco end : enderecos) {
			pessoa.addEndereco(end);
		}

		try {
			//se for uma pessoa fisica, insere ou salva.
			if (pessoa instanceof PessoaFisica) {
				pessoaFisicaServiceBeanLocal.salvar((PessoaFisica) pessoa);
				pessoa = new Pessoa();
				tipoPessoa = "";
				cpf = "";
			} 
			//se for uma pessoa juridica, insere ou salva.
			else if (pessoa instanceof PessoaJuridica) {
				pessoaJuridicaServiceBeanLocal.salvar((PessoaJuridica) pessoa);
				pessoa = new Pessoa();
				tipoPessoa = "";
				cnpj = "";
			}
			setTelefones(new ArrayList<Telefone>());
			setEnderecos(new ArrayList<Endereco>());
			addMensagem(FacesMessage.SEVERITY_INFO, "Salvo com sucesso", "Salvo com sucesso");
		}
		//erro de cadastro de pessoa com e-mail igual.
		catch (EmailIgualException e) {
			// TODO: Colocar msg no propeties
			addMensagem(FacesMessage.SEVERITY_ERROR, "Erro Email: E-mail já cadastrado", "E-mail já cadastrado");
			return PageFactory.CADASTROPESSOA;
		}
		//erro de cadastro de pessoa fisica com cpf igual
		catch (CPFIgualException e) {
			log.warn(e.getMessage());
			addMensagem(FacesMessage.SEVERITY_ERROR, e.getMessage(), e.getMessage());
			// TODO Colocar msg no propeties
			return PageFactory.CADASTROPESSOA;
		}
		//erro de cadastro de pessoa juridica com CNPJ igual
		catch (CNPJIgualException e) {
			addMensagem(FacesMessage.SEVERITY_ERROR, "Erro CNPJ: CNPJ já cadastrado", "CNPJ já cadastrado");
			// TODO: Colocar msg no propeties
		}
		//erro inexperado.
		catch (Exception e) {
			log.error(e.getMessage());
			// TODO Colocar msg no propeties
			addMensagem(FacesMessage.SEVERITY_ERROR, "Erro desconhecido : " + e.getMessage(), "");
			e.printStackTrace();
		}

		// salvarEnderecos(enderecos, pessoa);
		// salvarTelefones(telefones, pessoa);
		// TODO: Colocar msg no propeties
		return PageFactory.CADASTROPESSOA;
	}

	/**
	 * Trata e persiste {@link List}<{@link Endereco}>
	 * 
	 * @param {@link List}<{@link Endereco}> enderecos
	 * @param {@link PessoaFisica} pessoaFisica
	 */
	public void salvarEnderecos(List<Endereco> enderecos, Pessoa pessoa) {
		for (Endereco endereco : enderecos) {
			endereco.setPessoa(pessoa);
			enderecoServiceBeanLocal.salvar(endereco);
		}
	}

	/**
	 * Trata de persiste uma {@link List}<{@link Telefone}>
	 * 
	 * @param {@link List}<{@link Telefone}> telefones
	 * @param {@link PessoaFisica} pessoaFisica
	 */
	public void salvarTelefones(List<Telefone> telefones, Pessoa pessoa) {
		for (Telefone telefone : telefones) {
			telefone.setPessoa(pessoa);
			telefone.setCodigoPais("55");
			telefone.setCodigoEstado(telefone.getNumero().substring(0, 2));
			telefone.setNumero(telefone.getNumero().substring(3, telefone.getNumero().length()).replaceAll("-", ""));
			telefoneServiceBeanLocal.salvar(telefone);
		}
	}

	/**
	 * @return the tipoPessoa
	 */
	public String getTipoPessoa() {
		return tipoPessoa;
	}

	/**
	 * @param tipoPessoa
	 *            the tipoPessoa to set
	 */
	public void setTipoPessoa(String tipoPessoa) {
		this.tipoPessoa = tipoPessoa;
	}

	/**
	 * Adiciona telefone a lista de {@link PessoaFisica}
	 * 
	 * @return
	 */
	public String addTelefone() {
		//telefone.setPessoa(pessoa);
		telefone.setCodigoPais("+55");
		telefone.setCodigoEstado(telefone.getNumero().substring(0, 2));
		telefone.setNumero(telefone.getNumero().substring(3).replace("-", ""));
		telefones.add(telefone);
		telefone = new Telefone();

		return PageFactory.CADASTROPESSOA;
	}

	/**
	 * Adiciona endereço na lista de {@link PessoaFisica}
	 * 
	 * @return {@link PageFactory}.CADASTROPESSOA
	 */
	public String addEndereco() {
		try {
			if (Util.isEmpty(getEndereco().getLogradouro()) || Util.isEmpty(getEndereco().getNumero()) || Util.isEmpty(getEndereco().getBairro()) || Util.isEmpty(getEndereco().getUf())
					|| Util.isEmpty(getEndereco().getCidade()) || Util.isEmpty(getEndereco().getCep())) {
				throw new EnderecoErradoException();
			} else {
				enderecos.add(endereco);
				endereco = new Endereco();
			}

		} catch (EnderecoErradoException e) {
			if (Util.isEmpty(getEndereco().getLogradouro())) {
				addMensagem("logradouro", FacesMessage.SEVERITY_ERROR, getResourceBundle().getString("javax.faces.component.UIInput.REQUIRED"), null);
			}
			if (Util.isEmpty(getEndereco().getNumero())) {
				addMensagem("numero", FacesMessage.SEVERITY_ERROR, getResourceBundle().getString("javax.faces.component.UIInput.REQUIRED"), null);
			}
			if (Util.isEmpty(getEndereco().getBairro())) {
				addMensagem("bairro", FacesMessage.SEVERITY_ERROR, getResourceBundle().getString("javax.faces.component.UIInput.REQUIRED"), null);
			}
			if (Util.isEmpty(getEndereco().getUf())) {
				addMensagem("uf", FacesMessage.SEVERITY_ERROR, getResourceBundle().getString("javax.faces.component.UIInput.REQUIRED"), null);
			}
			if (Util.isEmpty(getEndereco().getCidade())) {
				addMensagem("cidade", FacesMessage.SEVERITY_ERROR, getResourceBundle().getString("javax.faces.component.UIInput.REQUIRED"), null);
			}
			if (Util.isEmpty(getEndereco().getCep())) {
				addMensagem("cep", FacesMessage.SEVERITY_ERROR, getResourceBundle().getString("javax.faces.component.UIInput.REQUIRED"), null);
			}
			return PageFactory.CADASTROPESSOA;
		}
		return PageFactory.CADASTROPESSOA;
	}
	
	public void onCompleteAlterarPessoa(){
		
	}
	
	public List<Pessoa> listarPessoasFisicas(String nome){
		return pessoaServiceBeanLocal.listar(nome);
	}

	/**
	 * @return the telefone
	 */
	public Telefone getTelefone() {
		return telefone;
	}

	/**
	 * @param telefone
	 *the telefone to set
	 */
	public void setTelefone(Telefone telefone) {
		this.telefone = telefone;
	}

	/**
	 * @return the endereco
	 */
	public Endereco getEndereco() {
		return endereco;
	}

	/**
	 * @param endereco
	 *the endereco to set
	 */
	public void setEndereco(Endereco endereco) {
		this.endereco = endereco;
	}

	/**
	 * @return the enderecos
	 */
	public List<Endereco> getEnderecos() {
		return enderecos;
	}

	/**
	 * @param enderecos
	 * the enderecos to set
	 */
	public void setEnderecos(List<Endereco> enderecos) {
		this.enderecos = enderecos;
	}

	/**
	 * @return the telefones
	 */
	public List<Telefone> getTelefones() {
		return telefones;
	}

	/**
	 * @param telefones
	 *the telefones to set
	 */
	public void setTelefones(List<Telefone> telefones) {
		this.telefones = telefones;
	}

	/**
	 * lista todas os objetos {@link PessoaFisica}
	 * 
	 * @return {@link List}<{@link PessoaFisica}>
	 */
	public Set<PessoaFisica> listarPessoas() {
		return pessoaFisicaServiceBeanLocal.recuperarTodasAsPessoas();
	}

	/**
	 * @return the pessoa
	 */
	public Pessoa getPessoa() {
		return pessoa;
	}

	/**
	 * Configura o atributo pessoa da classe, decidindo o atributo tipoPessoa
	 * de acordo com o tipo da classe. Dessemodo as expressões na tela serão
	 * avaliadas corretamente, mostrando os campos corretos.
	 * Faz o reflexo entre a lista de endereços e telefones dentro de pessoa
	 * para o do menaged bean para lista-los na tela pelo prime faces.
	 * @param pessoa
	 */
	public void setPessoa(Pessoa pessoa) {
		if (pessoa.getTelefones() != null && pessoa.getTelefones().size() > 0) {
			if (telefones != null && telefones.size() > 0) {
				for (Telefone tel : telefones) {
					pessoa.addTelefone(tel);
				}
			}
			telefones.clear();
			telefones.addAll(pessoa.getTelefones());
		}
		if (pessoa.getEnderecos() != null && pessoa.getEnderecos().size() > 0) {
			if (enderecos != null && enderecos.size() > 0) {
				for (Endereco end : enderecos) {
					pessoa.addEndereco(end);
				}
			}
			enderecos.clear();
			enderecos.addAll(pessoa.getEnderecos());
		}
		if (pessoa instanceof PessoaFisica) {
			setCpf(((PessoaFisica)pessoa).getCpf());
			setCnpj("");
			setTipoPessoa("pf");
		}
		else if (pessoa instanceof PessoaJuridica) {
			setCnpj(((PessoaJuridica)pessoa).getCnpj());
			setCpf("");
			setTipoPessoa("pj");
		}
		this.pessoa = pessoa;
	}

	/**
	 * @return the cpf
	 */
	public String getCpf() {
		return cpf;
	}

	/**
	 * @param cpf
	 *            the cpf to set
	 */
	public void setCpf(String cpf) {
		this.cpf = cpf;
	}

	/**
	 * @return the cnpj
	 */
	public String getCnpj() {
		return cnpj;
	}

	/**
	 * @param cnpj
	 *            the cnpj to set
	 */
	public void setCnpj(String cnpj) {
		this.cnpj = cnpj;
	}

	/**
	 * @return the perfis
	 */
	public List<Perfil> getPerfis() {
		return perfis;
	}

	/**
	 * @param perfis the perfis to set
	 */
	public void setPerfis(List<Perfil> perfis) {
		this.perfis = perfis;
	}
}
